/*
	This file is part of Vajolet.

    Vajolet is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Vajolet is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Vajolet.  If not, see <http://www.gnu.org/licenses/>
*/


//#include <xmmintrin.h>
#include "move.h"
#include "board.h"
#include "data.h"
#include "gameline.h"
#include "movegen.h"
#include <assert.h>

score Move::gain() const{
	score gain=Board::PIECESCORE[board.square[to]%Board::emptyBitmap];
	if(flags==fpromotion){
		gain+=Board::PIECESCORE[Board::whiteQueens+promotion]-Board::PIECESCORE[Board::whitePawns];
	}
	return gain;
}

score Move::MVVLVA() const {
	score res=Board::PIECESCORE[board.square[to]%Board::emptyBitmap] + (board.square[from]);
	if(flags== fenpassant){
		res+=Board::PIECESCORE[Board::whitePawns];
	}else if(flags== promotion){
		res+=-Board::PIECESCORE[Board::whitePawns]+board.PIECESCORE[Board::whiteQueens+promotion];
	}
	return res;
}


void Move::displayUci(void){

	//from
	std::cout<<char('a'+FILES[from]);
	std::cout<<char('1'+RANKS[from]);

	
	//to
	std::cout<<char('a'+FILES[to]);
	std::cout<<char('1'+RANKS[to]);
	//promotion
	if(flags == Move::fpromotion){
		std::cout << Board::PIECECHARS[promotion+Board::whiteQueens];
	}

	std::cout.flush();
}


bool Move::isCapture() const {
	return board.square[to]!=Board::empty || flags==fenpassant;
	/*if(board.square[to]!=Board::empty || flags==fenpassant ){
		return true;
	}
	return false;*/
}
bool Move::isCaptureOrPromotion() const {
	return board.square[to]!=Board::empty || flags==fenpassant || (flags==fpromotion);
	/*if(board.square[to]!=Board::empty || flags==fenpassant || (flags==fpromotion)){
		return true;
	}
	return false;*/
}

std::string Move::display(bool toStdout)
{
	std::string s;
	if(packed==0){
		s="NULL MOVE";
	}else if(flags == Move::fcastle){						//castle
		if((from==E1 && to==C1) ||(from==E8 && to==C8)){
			s="O-O-O";
		}else if((from==E1 && to==G1) ||(from==E8 && to==G8)){
			s="O-O";
		}
	}else if(board.square[from]==Board::whitePawns || board.square[from]==Board::blackPawns){// mosse di pedone
		//cattura
		s="";
		if(board.square[to]!=Board::empty || flags == Move::fenpassant){
			s+=char('a'+FILES[from]);
			s+="x";
		}

		s+=char('a'+FILES[to]);
		s+=char('1'+RANKS[to]);

		//enpassant
		if(flags == Move::fenpassant){
			s+=" e.p.";
		}

		//promotion
		if(flags == Move::fpromotion){
			s+="=";
			s+= Board::PIECECHARS[promotion+Board::whiteQueens];
		}

		board.makeMove(*this);
		if(board.isOwnKingAttacked()){
			s+="+";
		}
		board.unmakeMove();
	}
	else{

		//mosse non di pedone


		Movegen mg(0);
		mg.genAll();
		int numeroMosseCompatibili=0;
		int numeroColonneCompatibili=0;
		int numeroTraverseCompatibili=0;
		if(board.square[to]!=Board::empty){
			// capture
			for(int i=0;i<mg.captureLastMove;i++){
				if((mg.captureMoves[i].packed != packed) && mg.captureMoves[i].to==to && board.square[mg.captureMoves[i].from]==board.square[from]){
					numeroMosseCompatibili++;
					if(RANKS[from]==RANKS[mg.captureMoves[i].from]){
						numeroTraverseCompatibili++;
					}
					if(FILES[from]==FILES[mg.captureMoves[i].from]){
						numeroTraverseCompatibili++;
					}
				}
			}
		}
		else{
			//quiet
			for(int i=0;i<mg.quietLastMove;i++){
				if((mg.quietMoves[i].packed != packed) && mg.quietMoves[i].to==to && board.square[mg.quietMoves[i].from]==board.square[from]){
					numeroMosseCompatibili++;
					if(RANKS[from]==RANKS[mg.quietMoves[i].from]){
						numeroTraverseCompatibili++;
					}
					if(FILES[from]==FILES[mg.quietMoves[i].from]){
						numeroColonneCompatibili++;
					}
				}
			}
		}
		
		// piece
		s= Board::PIECECHARS[board.square[from]];

		if(numeroMosseCompatibili!=0){
			if(!numeroColonneCompatibili && !numeroTraverseCompatibili){
				s+=char('a'+FILES[from]);
			}else if(!numeroColonneCompatibili && numeroTraverseCompatibili){
				s+=char('a'+FILES[from]);
			}else if(numeroColonneCompatibili && !numeroTraverseCompatibili){
				s+=char('1'+RANKS[from]);
			}else if(numeroColonneCompatibili && numeroTraverseCompatibili){
				s+=char('1'+RANKS[from]);
				s+=char('a'+FILES[from]);
			}
		}
	

		//capture
		if(board.square[to]!=Board::empty){
			s+="x";
		}
		//to
		s+=char('a'+FILES[to]);
		s+=char('1'+RANKS[to]);
	

		board.makeMove(*this);
		if(board.isOwnKingAttacked()){
			s+="+";
		}
		board.unmakeMove();
	}

	if(toStdout){
		std::cout<<s;
	}
	return s;

}

/*void Move::makeMove(void){
	assert(board.gameLineIndex<MAX_GAME_LENGTH);
	bitMap mbTo =BITSET[to];
	bitMap mbfrom =BITSET[from];
	bitMap mbFromTo =mbfrom^mbTo;
	//salva dati importanti nella gameLineRecord
	
	GamelineRecord & glr=board.gameLine[board.gameLineIndex];
	Board::bitboardIndex capturedPiece = board.square[to];
	Board::bitboardIndex piece= board.square[from];

	//copyTo(glr.move);
	glr.move.packed=packed;
	glr.castleRights=board.castleRights;
	glr.epSquare=board.epSquare;
	glr.fiftyMoveCnt=board.fiftyMoveCnt;
	glr.hashKey=board.hashKey;
	glr.pawnKey=board.pawnKey;
	glr.materialKey=board.materialKey;

	glr.Material=board.Material;
	//glr.totalWhitePawns=board.totalWhitePawns;
	//glr.totalBlackPawns=board.totalBlackPawns;
	glr.totalWhitePieces=board.totalWhitePieces; 
	glr.totalBlackPieces=board.totalBlackPieces;
	glr.capturedPiece=capturedPiece;
	glr.kingInCheck=board.kingInCheck;

	board.kingInCheck=Board::dontKnow;

	board.gameLineIndex++;

	//fine salvataggio

	//if(board.epSquare){// non serve perche' ep[0]=0 (impostato a mano!) 1.2% speedup nel MOVEGEN
		board.hashKey ^= Board::KEY.ep[board.epSquare]^Board::KEY.side^Board::KEY.keys[from][piece]^Board::KEY.keys[to][piece];
	//}
	board.epSquare=0;								//azzero epsquare
	board.fiftyMoveCnt++;							//incremento contatore 50 mosse



	board.boards[piece]^=mbFromTo;	//muovo il pezzo sulle bitboard

	
	if(isPawn(piece)){
		board.fiftyMoveCnt=0;
		board.pawnKey^=Board::KEY.keys[from][piece];
		board.pawnKey^=Board::KEY.keys[to][piece];
		if (to-from==16)
		{
			board.epSquare = from+8;
			board.hashKey ^= Board::KEY.ep[from+8];
		}
		else if (from-to==16)
		{
			board.epSquare = from-8;
			board.hashKey ^= Board::KEY.ep[from-8];
		}
	}


	//CATTURE
	if(capturedPiece){																
		board.fiftyMoveCnt=0;							//resetto contatore 50 mosse 							
		board.boards[capturedPiece]^=mbTo;	//elimino il pezzo catturato dalla bitboard
		board.hashKey ^= Board::KEY.keys[to][capturedPiece];
		board.materialKey ^=Board::KEY.keys[board.pieceCount[capturedPiece]][capturedPiece];
		board.pieceCount[capturedPiece]--;
		board.materialKey ^=Board::KEY.keys[board.pieceCount[capturedPiece]][capturedPiece];
		board.Material-=Board::PIECESCORE[capturedPiece];
		if(board.nextMove){// black to play
			if(isPawn(capturedPiece)){
				//board.totalWhitePawns-=Board::PIECESCORE[capturedPiece];
				board.pawnKey ^= Board::KEY.keys[to][capturedPiece];
			}else{
				board.totalWhitePieces-=Board::PIECESCORE[capturedPiece];
			}
		}else{
			if(isPawn(capturedPiece)){
				//board.totalBlackPawns+=Board::PIECESCORE[capturedPiece];
				board.pawnKey ^= Board::KEY.keys[to][capturedPiece];
			}else{
				board.totalBlackPieces+=Board::PIECESCORE[capturedPiece];
			}
		}
	}


	board.square[to]=piece;				//muovo il pezzo nello square , contiene gia' il codice della cattura
	board.square[from]=Board::empty;




	//AGGIORNAMENTO  whitepieces/blackpieces bitboard
	board.boards[Board::whitePieces+board.nextMove]^=mbFromTo;
	if(capturedPiece)board.boards[Board::blackPieces-board.nextMove]^=mbTo;// se e' una cattura elimino il pezzo avversario



	if(flags ){
		if(piece==Board::whitePawns)
		{
		
			if(flags == Move::fenpassant){
				board.square[to-8]=Board::empty;
				board.boards[Board::blackPawns]^=BITSET[to-8];
				board.boards[Board::blackPieces]^=BITSET[to-8];
				board.materialKey ^=Board::KEY.keys[board.pieceCount[Board::blackPawns]][Board::blackPawns];
				board.pieceCount[Board::blackPawns]--;
				board.materialKey ^=Board::KEY.keys[board.pieceCount[Board::blackPawns]][Board::blackPawns];
				board.hashKey^= Board::KEY.keys[to-8][Board::blackPawns];
				board.pawnKey^= Board::KEY.keys[to-8][Board::blackPawns];
				//board.totalBlackPawns+=Board::PIECESCORE[Board::blackPawns];
				board.Material-=Board::PIECESCORE[Board::blackPawns];
			}else
			if(flags== Move::fpromotion){ // promozione
				board.square[to]=(Board::bitboardIndex)(Board::whiteQueens+promotion);
				board.boards[Board::whitePawns]^=mbTo; // elimino il pedone
				//board.boards[Board::whitePieces]^=mbTo; // aggiungo il pezzo
				board.pawnKey ^= Board::KEY.keys[to][Board::whitePawns];
				board.materialKey ^=Board::KEY.keys[board.pieceCount[Board::whitePawns]][Board::whitePawns];
				board.pieceCount[Board::whitePawns]--;
				board.materialKey ^=Board::KEY.keys[board.pieceCount[Board::whitePawns]][Board::whitePawns];
				board.materialKey ^=Board::KEY.keys[board.pieceCount[Board::whiteQueens+promotion]][Board::whiteQueens+promotion];
				board.pieceCount[Board::whiteQueens+promotion]++;
				board.materialKey ^=Board::KEY.keys[board.pieceCount[Board::whiteQueens+promotion]][Board::whiteQueens+promotion];
				board.hashKey ^= Board::KEY.keys[to][Board::whitePawns]^Board::KEY.keys[to][Board::whiteQueens+promotion];
				board.boards[Board::whiteQueens+promotion]^=mbTo; // aggiungo il pezzo
				//board.totalWhitePawns-=Board::PIECESCORE[Board::whitePawns];
				board.totalWhitePieces+=Board::PIECESCORE[Board::whiteQueens+promotion];
				board.Material-=Board::PIECESCORE[Board::whitePawns];
				board.Material+=Board::PIECESCORE[Board::whiteQueens+promotion];

			}
		}else if(piece==Board::blackPawns){
			if(flags == Move::fenpassant){
				board.square[to+8]=Board::empty;
				board.boards[Board::whitePawns]^=BITSET[to+8];
				board.boards[Board::whitePieces]^=BITSET[to+8];
				board.materialKey ^=Board::KEY.keys[board.pieceCount[Board::whitePawns]][Board::whitePawns];
				board.pieceCount[Board::whitePawns]--;
				board.materialKey ^=Board::KEY.keys[board.pieceCount[Board::whitePawns]][Board::whitePawns];
				board.hashKey^= Board::KEY.keys[to+8][Board::whitePawns];
				board.pawnKey^= Board::KEY.keys[to+8][Board::whitePawns];
				//board.totalWhitePawns-=Board::PIECESCORE[Board::whitePawns];
				board.Material-=Board::PIECESCORE[Board::whitePawns];
			}else if(flags== Move::fpromotion){ // promozione
				board.square[to]=(Board::bitboardIndex)(Board::blackQueens+promotion);
				board.boards[Board::blackPawns]^=mbTo; // elimino il pedone
				//board.boards[Board::blackPieces]^=mbTo; // aggiungo il pezzo
				board.pawnKey ^= Board::KEY.keys[to][Board::blackPawns];

				board.materialKey ^=Board::KEY.keys[board.pieceCount[Board::blackPawns]][Board::blackPawns];
				board.pieceCount[Board::blackPawns]--;
				board.materialKey ^=Board::KEY.keys[board.pieceCount[Board::blackPawns]][Board::blackPawns];

				board.materialKey ^=Board::KEY.keys[board.pieceCount[Board::blackQueens+promotion]][Board::blackQueens+promotion];
				board.pieceCount[Board::blackQueens+promotion]++;
				board.materialKey ^=Board::KEY.keys[board.pieceCount[Board::blackQueens+promotion]][Board::blackQueens+promotion];

				board.hashKey ^= Board::KEY.keys[to][Board::blackPawns]^Board::KEY.keys[to][Board::blackQueens+promotion];
				board.boards[Board::blackQueens+promotion]^=mbTo; // aggiungo il pezzo
				//board.totalBlackPawns+=Board::PIECESCORE[Board::blackPawns];
				board.totalBlackPieces-=Board::PIECESCORE[Board::blackQueens+promotion];
				board.Material-=Board::PIECESCORE[Board::blackPawns];
				board.Material+=Board::PIECESCORE[Board::blackQueens+promotion];


			}
		}

	
		if(flags == fcastle){
			if(to== G1){
				board.boards[Board::whiteRooks]^=(BITSET[F1]| BITSET[H1]);
				board.boards[Board::whitePieces]^=(BITSET[F1] | BITSET[H1]);
				board.square[F1]=Board::whiteRooks;
				board.square[H1]=Board::empty;
				board.hashKey^=Board::KEY.keys[F1][Board::whiteRooks]^Board::KEY.keys[H1][Board::whiteRooks] ;
			
			}else if(to== C1){
				board.boards[Board::whiteRooks]^=(BITSET[D1]| BITSET[A1]);
				board.boards[Board::whitePieces]^=(BITSET[D1]| BITSET[A1]);
				board.square[D1]=Board::whiteRooks;
				board.square[A1]=Board::empty;
				board.hashKey^=Board::KEY.keys[A1][Board::whiteRooks]^Board::KEY.keys[D1][Board::whiteRooks] ;
			}else if(to== G8){
				board.boards[Board::blackRooks]^=(BITSET[F8]| BITSET[H8]);
				board.boards[Board::blackPieces]^=(BITSET[F8]| BITSET[H8]);
				board.square[F8]=Board::blackRooks;
				board.square[H8]=Board::empty;
				board.hashKey^=Board::KEY.keys[F8][Board::blackRooks]^Board::KEY.keys[H8][Board::blackRooks] ;
			}else if(to== C8){
				board.boards[Board::blackRooks]^=(BITSET[D8]| BITSET[A8]);
				board.boards[Board::blackPieces]^=(BITSET[D8]| BITSET[A8]);
				board.square[D8]=Board::blackRooks;
				board.square[A8]=Board::empty;
				board.hashKey^=Board::KEY.keys[D8][Board::blackRooks]^Board::KEY.keys[A8][Board::blackRooks] ;
			}
		}
	}

	if(board.castleRights){
		// aggiornamento castle Rights
		if(from==E1){
			if(board.castleRights & board.wCastleOO){
				board.hashKey^=Board::KEY.castlingRight[board.wCastleOO];
			}
			if(board.castleRights & board.wCastleOOO){
				board.hashKey^=Board::KEY.castlingRight[board.wCastleOOO];
			}
			board.castleRights &=~(board.wCastleOO |board.wCastleOOO );
		}else
		if(from==E8){
			if(board.castleRights & board.bCastleOO){
				board.hashKey^=Board::KEY.castlingRight[board.bCastleOO];
			}
			if(board.castleRights & board.bCastleOOO){
				board.hashKey^=Board::KEY.castlingRight[board.bCastleOOO];
			}
			board.castleRights &=~(board.bCastleOO |board.bCastleOOO );
		}
		if(from == A1 || to == A1 ){
			if(board.castleRights & board.wCastleOOO){
				board.hashKey^=Board::KEY.castlingRight[board.wCastleOOO];
			}
			board.castleRights &=~(board.wCastleOOO);
		}
		if(from == H1 || to == H1){
			if(board.castleRights & board.wCastleOO){
				board.hashKey^=Board::KEY.castlingRight[board.wCastleOO];
			}
			board.castleRights &=~(board.wCastleOO);
		}
		if(from == A8 || to == A8){
			if(board.castleRights & board.bCastleOOO){
				board.hashKey^=Board::KEY.castlingRight[board.bCastleOOO];
			}
			board.castleRights &=~(board.bCastleOOO);
		}
		if(from == H8 || to == H8){
			if(board.castleRights & board.bCastleOO){
				board.hashKey^=Board::KEY.castlingRight[board.bCastleOO];
			}
			board.castleRights &=~(board.bCastleOO);
		}
	}

	char * tt= (char*)board.transTT.firstEntry(board.hashKey);
//	_mm_prefetch(tt, _MM_HINT_T2);
//	_mm_prefetch(tt+64, _MM_HINT_T2); // 64 bytes ahead
	board.boards[board.occupiedSquares]=board.boards[board.whitePieces]|board.boards[board.blackPieces];

	
	board.nextMove = (Board::eNextMove)(Board::black-board.nextMove);	//inverto il colore attivo

#ifdef _DEBUG_MAKEMOVE
	board.checkBoard();
#endif
}
*/



